﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using App.Utility.Paging;

namespace App.Utility.Paging
{
    /// <summary>
    /// Written By: Charles Cook
    /// </summary>
    public static class HtmlHelperExtensions
    {
        /// <summary>
        /// Defines the format for rending a page listing with PageListing
        /// </summary>
        public class PageListingStyle
        {
            public string FirstText { get; set; }
            public string PreviousText { get; set; }
            public string NextText { get; set; }
            public string LastText { get; set; }

            public bool NextEnabled { get; set; }
            public bool PreviousEnabled { get; set; }
            public bool FirstEnabled { get; set; }
            public bool LastEnabled { get; set; }

            public string PageFormatter { get; set; }
            public string PageListingFormatter { get; set; }
            public string ActionLinkFormatter { get; set; }
            public string CurrentFormatter { get; set; }

            public string DeliminatorText { get; set; }

            public string PageListingClass { get; set; }

        }

        /// <summary>
        /// Renders a pager for a PageResponse using a default style with a class name 'pager' against the QueryString parameter "page" and with a wrap of five.
        /// </summary>
        /// <param name="html"></param>
        /// <param name="pageResponse">The pageable data source</param>
        /// <returns>Rendered paging</returns>
        public static string PageListing(this HtmlHelper html, IPagedList pageResponse)
        {
            return PageListing(html, pageResponse, 5, "page");
        }

        /// <summary>
        /// Renders a pager for a PageResponse using a default style with a class name 'pager' against the QueryString parameter "page".
        /// </summary>
        /// <param name="html"></param>
        /// <param name="pageResponse">The pageable data source</param>
        /// <param name="wrapCount">The number of items to wrap the index with. (ex: 1 2 '3' 4 5 has a wrap of two if the current page is three)</param>
        /// <returns>Rendered paging</returns>
        public static string PageListing(this HtmlHelper html, IPagedList pageResponse, int wrapCount)
        {
            return PageListing(html, pageResponse, wrapCount, "page");
        }

        /// <summary>
        /// Renders a pager for a PageResponse using a default style with a class name 'pager' with a wrap of five.
        /// </summary>
        /// <param name="html"></param>
        /// <param name="pageResponse">The pageable data source</param>
        /// <param name="queryStringParameterName">The query string parameter to target in the links</param>
        /// <returns>Rendered paging</returns>
        public static string PageListing(this HtmlHelper html, IPagedList pageResponse, string queryStringParameterName)
        {
            return PageListing(html, pageResponse, 5, queryStringParameterName);
        }

        /// <summary>
        /// Renders a pager for a PageResponse using a default style with a class name 'pager'.
        /// </summary>
        /// <param name="html"></param>
        /// <param name="pageResponse">The pageable data source</param>
        /// <param name="wrapCount">The number of items to wrap the index with. (ex: 1 2 '3' 4 5 has a wrap of two if the current page is three)</param>
        /// <param name="queryStringParameterName">The query string parameter to target in the links</param>
        /// <returns>Rendered paging</returns>
        public static string PageListing(this HtmlHelper html, IPagedList pageResponse, int wrapCount, string queryStringParameterName)
        {
            return PageListing(html, pageResponse, wrapCount, queryStringParameterName, new PageListingStyle
            {
                FirstEnabled = true,
                LastEnabled = true,
                NextEnabled = true,
                PreviousEnabled = true,
                FirstText = "first",
                LastText = "last",
                NextText = "next",
                PreviousText = "prev",
                PageFormatter = "{0}",
                DeliminatorText = " ",
                PageListingFormatter = "<div class=\"{1}\">{0}</div>",
                ActionLinkFormatter = "<a href=\"{0}\">{1}</a>",
                PageListingClass = "pager",
                CurrentFormatter = "<strong>{0}</strong>"
            });
        }

        /// <summary>
        /// Renders a pager for a PageResponse using the style provided.
        /// </summary>
        /// <param name="html"></param>
        /// <param name="pageResponse">The pageable data source</param>
        /// <param name="wrapCount">The number of items to wrap the index with. (ex: 1 2 '3' 4 5 has a wrap of two if the current page is three)</param>
        /// <param name="queryStringParameterName">The query string parameter to target in the links</param>
        /// <param name="pageListingStyle">The style for rendering the html</param>
        /// <returns>Rendered paging</returns>
        public static string PageListing(this HtmlHelper html, IPagedList pageResponse, int wrapCount, string queryStringParameterName, PageListingStyle pageListingStyle)
        {
            StringBuilder builder = new StringBuilder();

            if (pageListingStyle.FirstEnabled)
            {
                if (pageResponse.PageIndex == 0)
                {
                    builder.Append(pageListingStyle.FirstText);
                }
                else
                {
                    builder.Append(CreateLink(1, pageListingStyle.FirstText, queryStringParameterName, html.ViewContext, pageListingStyle));
                }

                builder.Append(pageListingStyle.DeliminatorText);
            }

            if (pageListingStyle.PreviousEnabled)
            {
                if (pageResponse.IsPreviousPage)
                {
                    builder.Append(CreateLink(pageResponse.PageIndex, pageListingStyle.PreviousText, queryStringParameterName, html.ViewContext, pageListingStyle));
                    builder.Append(pageListingStyle.DeliminatorText);
                }
            }

            for (int i = pageResponse.PageIndex - wrapCount; i < pageResponse.PageIndex; i++)
                if (i >= 0)
                {
                    builder.Append(CreateLink(i + 1, String.Format(pageListingStyle.PageFormatter, Convert.ToString(i + 1)), queryStringParameterName, html.ViewContext, pageListingStyle));
                    builder.Append(pageListingStyle.DeliminatorText);
                }

            builder.Append(CreateLink(pageResponse.PageIndex + 1, String.Format(pageListingStyle.CurrentFormatter, Convert.ToString(pageResponse.PageIndex + 1)), queryStringParameterName, html.ViewContext, pageListingStyle));
            builder.Append(pageListingStyle.DeliminatorText);

            for (int i = pageResponse.PageIndex + 1; i < pageResponse.PageIndex + wrapCount; i++)
                if (i < pageResponse.TotalPages)
                {
                    builder.Append(CreateLink(i + 1, String.Format(pageListingStyle.PageFormatter, Convert.ToString(i + 1)), queryStringParameterName, html.ViewContext, pageListingStyle));
                    builder.Append(pageListingStyle.DeliminatorText);
                }

            if (pageListingStyle.NextEnabled)
            {
                if (pageResponse.IsNextPage)
                {
                    builder.Append(CreateLink(pageResponse.PageIndex + 2, pageListingStyle.NextText, queryStringParameterName, html.ViewContext, pageListingStyle));
                    builder.Append(pageListingStyle.DeliminatorText);
                }
            }

            if (pageListingStyle.LastEnabled)
            {
                if (pageResponse.PageIndex + 1 == pageResponse.TotalPages)
                {
                    builder.Append(pageListingStyle.LastText);
                }
                else
                {
                    builder.Append(CreateLink(pageResponse.TotalPages, pageListingStyle.LastText, queryStringParameterName, html.ViewContext, pageListingStyle));
                }
            }

            return String.Format(pageListingStyle.PageListingFormatter, builder, pageListingStyle.PageListingClass);
        }

        private static string CreateLink(int pageNumber, string text, string queryStringParameterName, ViewContext context, PageListingStyle pageListingStyle)
        {
            string queryString = context.HttpContext.Request.QueryString.Duplicate()
                .ChangeField(queryStringParameterName, Convert.ToString(pageNumber))
                .WriteLocalPathWithQuery(context.HttpContext.Request.Url);
            return string.Format(pageListingStyle.ActionLinkFormatter, queryString, text);
        }


        public static string PageSorting(this HtmlHelper html, PagingSet pagingSet, string sortField, string displayText)
        {
            return String.Format(pagingSet.ActionLinkFormatter, html.ViewContext.HttpContext.Request.QueryString.Duplicate()
                .ChangeField(pagingSet.SortByQueryStringParameterName, sortField)
                .NegateField(pagingSet.DirectionQueryStringParameterName)
                .WriteLocalPathWithQuery(html.ViewContext.HttpContext.Request.Url), displayText);
                
        }

        public static string FilterInput(this HtmlHelper html, PagingSet pagingSet, string buttonText)
        {
            string filterCheckBoxTemplate = @"<input type=""checkbox"" name=""{0}"" value=""{1}"" id=""{1}"" {2}/><label for=""{1}"">{1}</label>";
            List<string> filteredFields = pagingSet.MatchFiltersFromQueryString(html.ViewContext.HttpContext);
            StringBuilder sbFilterOptions = new StringBuilder();

            sbFilterOptions.Append(
                String.Format(filterCheckBoxTemplate,
                pagingSet.FilterByQueryStringParameterName,
                pagingSet.FilterAllText,
                filteredFields.Count==pagingSet.FilterFields.Count ? " checked=\"yes\"" : ""));

            for (int i = 0; i < pagingSet.FilterFields.Count; i++)
            {
                sbFilterOptions.Append(
                    String.Format(filterCheckBoxTemplate,
                    pagingSet.FilterByQueryStringParameterName,
                    pagingSet.FilterFields[i],
                    filteredFields.Contains(pagingSet.FilterFields[i])?" checked=\"yes\"":""));
            }

            return String.Format(pagingSet.FilterInputFormatter,
                html.ViewContext.HttpContext.Request.FilePath,
                buttonText, 
                pagingSet.FilterQueryStringParameterName,
                html.ViewContext.HttpContext.Request.QueryString.Duplicate().RemoveItem(pagingSet.FilterQueryStringParameterName).RemoveItem(pagingSet.FilterByQueryStringParameterName).WriteQueryToInputFields(),
                html.ViewContext.HttpContext.Request.QueryString[pagingSet.FilterQueryStringParameterName],
                sbFilterOptions.ToString());
        }
    }
}
